﻿#define  _CRT_SECURE_NO_WARNINGS



#include "Date.h"




// 日期计算器全，const成员函数，取地址操作符重载，const取地址操作符重载，构造函数初始化列表








// 类和对象（中）

void TestDate1()
{
	Date d1(2023, 4, 7);
	d1.Print();

	//Date d2(2023, 2, 39);
	//d2.Print();

	Date d2 = d1 + 1000;
	d2.Print();
	d1.Print();

	Date d3 = d1;
	d3 += 1000;
	d3.Print();

}


void TestDate2()
{
	Date d1(2023, 4, 7);
	d1.Print();

	++d1;// d1.operator++();
	d1.Print();

	d1++;// d1.operator++(0);// 调用时 编译器随机传入一个整形值，作为函数实参
	d1.Print();

}


//void TestDate3()
//{
//	Date d1(2023, 4, 9);
//	d1.Print();
//
//	Date d2 = d1 - 100;
//	d1.Print();
//	d2.Print();
//
//	d1 -= 100;
//	d1.Print();
//
//}


//void TestDate4() 
//{
//	Date d1(2023, 4, 9);
//	d1.Print();
//
//	// 向前计算100天
//	d1 += -100;
//	d1.Print();
//
//	// 向后计算100天
//	d1 -= -100;
//	d1.Print();
//
//}


//
//void TestDate5()
//{
//	Date d1(2023, 4, 9);
//	d1.Print();
//
//	Date ret1 = --d1;
//	d1.Print();
//	ret1.Print();
//
//	Date ret2 = ++d1;
//	d1.Print();
//	ret2.Print();
//
//	Date ret3 = d1--;
//	d1.Print();
//	ret3.Print();
//
//	Date ret4 = d1++;
//	d1.Print();
//	ret4.Print();
//}




//void TestDate6()
//{
//	Date d1(2023, 4, 9);
//	d1.Print();
//
//	d1.operator++(0);
//
//}



void TestDate7()
{
	Date d1(2023, 4, 9);
	d1.Print();

	Date d2(2023, 5, 1);
	d2.Print();


	cout << d1 - d2 << endl;
	cout << d2 - d1 << endl;
}


void TestDate8()
{
	Date d1(2023, 4, 9);
	//d1.Print();
	cout << d1 << endl;

	Date d2(2023, 5, 1);
	//d2.Print();
	cout << d2 << endl;

	cout << d1 << endl << d2 << endl << d1 << endl << d2 << endl;
	// 
	// 
	// cout 是类对象
	// << 流插入运算符
	// 
	// 
	// 
	// 对 << 流插入运算符重载，且是对operator<<()的函数重载
	// 内置类型，对于<< 运算符 是iostream库中已经写好的operator<<() 运算符重载函数 的函数重载函数
	// 综上：才可以做到自动识别类型
	//int i = 1;
	//cout << i;// cout.operator<<(i)  ---  int 

	//double d = 1.11;
	//cout << d;// cout.operator<<(d)  ---  double 

}




void TestDate9()
{
	// 流提取
	Date d1;
	cin >> d1;
	cout << d1;
}




//int main()
//{
//	//TestDate1();
//	//TestDate2();
//	//TestDate3();
//	//TestDate4();
//	//TestDate5();
//	//TestDate6();
//	//TestDate7();
//	//TestDate8();
//	TestDate9();
//
//
//	return 0;
//}








// const成员

//class A
//{
//public:
//
//	// const成员
//
//
//	// 成员函数中 内部不改变成员变量的成员函数 ，最好都加上const修饰成员函数，规范this指针的操作范围
//	// 
//	// 
//	// 在类成员函数后面增加 const 本质修饰 *this默认形参
//	// this指针的类型为 const A*
//	void Print() const
//	{
//		cout << _a << endl;
//	}
//
//
//
//
//
//
//
//	// 最后两个默认成员函数：
//	// 实际上基本不用自己写，靠编译器自动生成即可解决问题
//	// 
//	// 
//	// 1.取地址操作符重载
//	A* operator&()
//	{
//		cout << "A* operator&()" << endl;
//		return this;
//	}
//
//	// 2.const取地址操作符重载
//	const A* operator&() const
//	{
//		cout << "const A* operator&() const" << endl;
//		return this;
//	}
//
//
//private:
//	int _a = 1;
//};
//
// 
// 
// 
// 
// 
// 
//int main()
//{
//	// const成员
//
//	const A aa;
//	aa.Print();
//	// 错误：
//	// 不能将“this”指针从“const A”转换为“A &”
//	// 
//	// coust A aa类型 应对应 const A* this类型
//	// 对应A* this 类型，会导致权限放大
//	
//	// 问题如何改变默认成员函数中隐含的 this 指针的类型
//	// 在类成员函数后面增加 const 本质修饰 *this默认形参
//	// this指针的类型为 const A*
//	// 此时为正确
//
//
//
//
//
//
//
//	// 最后两个默认成员函数：
//	// 实际上基本不用自己写，靠编译器自动生成即可解决问题
//	// 
//	// 
//	// 1.取地址操作符重载
//	A bb;
//	cout << &aa << endl;
//	cout << &bb << endl;
//
//	// 2.const取地址操作符重载
//	const A cc;
//	cout << &cc << endl;
//
// 
// 
// 
// 
// 
//	return 0;
//}














// [] 运算符重载，实例展示
// 
// 
// 
// 
//class Array
//{
//public:
//	int& operator[](const int i)
//	{
//		// 检查i是否越界
//		assert(i < 10);
//
//		return _a[i];
//	}
//
//	const int& operator[](const int i) const
//	{
//		// 检查i是否越界
//		assert(i < 10);
//
//		return _a[i];
//	}
//
//
//private:
//	int _a[10] = { 0 };
//	int _size = 0;
//};
//
//
//int main()
//{
//	Array a1;
//
//	for (int i = 0; i < 10; ++i)
//	{
//		// 实现顺序表初始化
//		// 自定义类型变量a 调用运算符重载函数int& operator[](int i)
//		a1[i] = i;
//	}
//
//	for (int i = 0; i < 10; ++i)
//	{
//		// 实现顺序表输出
//		// 自定义类型变量a 调用运算符重载函数int& operator[](int i)
//		cout << a1[i] << " ";
//	}
//	cout << endl;
//
//
//
//	const Array a2;
//
//	for (int i = 0; i < 10; ++i)
//	{
//		// 实现顺序表输出
//		// 自定义类型变量a 调用运算符重载函数int& operator[](int i)
//		cout << a2[i] << " ";
//	}
//
//	return 0;
//}


































// 类和对象（下）




// 构造函数
// 
// 1.构造函数体内赋值初始化
// 
// 
//class Date
//{
//public:
//	Date(int year, int month, int day)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//private:
//	int _year;
//	int _month;
//	int _day;
//};

















// 2.初始化列表

//class B
//{
//public:
//	B(int)
//		:_b(1)
//	{
//		cout << "B()" << endl;
//	}
//
//private:
//	int _b = 0;
//};



//class A
//{
//public:
//	// 构造函数，初始化列表
//	// 
//	// 1.那个实例化对象调用的构造函数，那么初始化列表就是该对象所有成员变量定义的位置
//	// 
//	// 2.无论是否显示的写在初始化列表中，编译器都会给每一个成员变量，在初始化列表定义并初始化
//	// 
//	// 
//	// 成员变量初始化 顺序：
//	// 1.先看成员变量声明的初始化值
//	// 
//	// 2.执行初始化列表，初始化列表中有显示写出 该成员变量对应的具体初始化值，编译器则优先采用显示写出的具体值
//	//				若该成员变量没有在初始化列表中显示给出，则编译器优先看是否给出初始化值声明：
//	//				
//	//							若有声明   ---   则采用此值，编译器使用此值在初始化列表中隐式初始化该成员变量
//	//							若无声明   ---   检查是否为必须在定义时初始化的类型成员变量
//	//									是必须定义初始化的变量  ---  直接报错
//	//								  不是必须定义初始化的变量  ---  则在初始化列表中编译器采用随机值对成员变量进行初始化
//	//												
//	// 
//	// 3.进入构造函数内部执行内容，此时所有成员变量已经完成定义并初始化了
//	// 
//	// 
//	// 
//	// 三种定义时必须初始化的类型：   这种类型的成员变量 必须在初始化列表 进行初始化，不能为随机值状态
//	// 
//	// 1.const成员变量 		
//	// const int _x;
//	// 
//	// 2.引用成员变量
//	// int& _ref;  
// 	//			
//	// 3.自定义类型成员变量（注意：该类没有默认构造函数，包括不能生成 默认生成构造函数 的情况下）
//	// B _bb;
//	//			当自定义类型的成员变量，所对应的类型中没有写默认构造函数时，
//	//			需要对该成员变量在初始化列表中，调用一个具体的构造函数，用来初始化该成员变量
//	//			
//	//			若B类型中有写出默认构造函数，则编译器会自动调用默认构造函数，不需要在初始化列表中显示调用构造函数
//	//			
//	// 
//	//
//	A()
//		:_a2(1)
//		, _ref(_a1)
//		, _bb(0)
//	{
//		_a1++;// 2
//		_a2--;// 0
//		// _x 为 1
//	}
//
//private:
//	int _a1 = 1;// 声明
//	int _a2 = 2;
//
//	// 为内置类型，默认构造函数不做处理
//	// C++11之后可以这样给出缺省值，让默认构造函数直接用缺省值来初始化 const修饰的成员变量
//	
//	// const成员变量 
//	const int _x = 1;// const修饰的变量，必须在定义的位置初始化它
//	// 引用成员变量
//	int& _ref;
//	// 自定义类型成员变量（注意：该类没有默认构造函数，包括不能生成 默认生成构造函数 的情况下）
//	B _bb;
//	// 
//	// 默认生成构造函数  ---  前提没有写构造函数
//	// 默认生成构造函数，只要需要且条件允许，可以逐步深入生成，直到为内置类型变量时停止生成
//	// 
//	// 对_bb进行定义初始化：
//	// 
//	// 1.若没有给出 _bb具体定义初始化值，则会在初始化列表中编译器直接调用B类型的默认构造函数，进行定义初始化
//	//		
//	//		若B类中没有写构造函数，则编译器自动生成一个B类的默认生成构造函数，对_bb进行定义初始化
//	//		
//	//		若B类中写了其他构造函数，但没有写出默认构造函数，
//	//		由于无法调用默认构造函数 且已经有写构造函数，编译器不会生成默认生成构造函数
//	//		----   报错：“B”: 没有合适的默认构造函数可用
//	// 
//	//
//	// 
//	// 2.若给出 _bb具体定义初始化值，则直接按照默认初始化值来定义初始化_bb，即可
//	// 
//	// 
//	// 
//	// 
//	// 
//	// 
//	// 
//	// 
//	// 
//	// 综上：（建议）
//	// 若需要显示初始化成员变量时，最好在构造函数初始化列表直接进行定义和初始化。
//	//
//	//
//};





//int main()
//{
//	A aa;// 对象整体的定义，每个成员什么时候定义？
//	
//
//	//const int i = 0;// const修饰的变量，必须在定义的位置初始化它
//	//// ---  必须给成员变量找一个定义的位置，不然像const这样的成员C++11之前 没办法初始化 
//
//
//
//
//  	return 0;
//}










// 练习：
class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}

	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};


int main() {
	A aa(1);
	aa.Print();
}


// 成员变量 在构造函数初始化列表中 的定义初始化顺序 按照成员变量的声明顺序进行 
// 
// 
// 顺序：
// 1.aa对象实例化，调用构造函数A(int a) 传入1，所以此时构造函数中 a == 1
// 2.按照声明顺序 定义初始化 成员函数
//			2.1.定义初始化_a2，使用数据_a1初始化，发现_a1未定义初始化
//				开始定义初始化_a1，采用随机值初始化_a1，所以_a2为随机值
//			2.2.定义初始化_a1，使用数据a == 1初始化，所以_a1 == 1
// 
// 



//A.输出1  1
//B.程序崩溃
//C.编译不通过
//D.输出1  随机值   ---  正确







// 总结：
// 
// 1.所有成员变量都会走初始化列表   ---   所有成员变量定义的地方
// 2.尽量在初始化列表进行初始化，有三个类型是必须的，其他的也尽量直接在初始化列表中就初始化了
// 
// 








